package com.filldream.fastboot.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.filldream.fastboot.base.entity.Menu;
import com.filldream.fastboot.base.entity.Role;
import com.filldream.fastboot.base.entity.RoleMenu;
import com.filldream.fastboot.base.entity.SystemUser;
import com.filldream.fastboot.base.mapper.RoleMapper;
import com.filldream.fastboot.base.mapper.RoleMenuMapper;
import com.filldream.fastboot.base.mapper.SystemUserMapper;
import com.filldream.fastboot.base.request.pc.role.RoleListSTO;
import com.filldream.fastboot.base.request.pc.roleMenu.SetRoleMenuSTO;
import com.filldream.fastboot.common.entity.B;
import com.filldream.fastboot.common.entity.ErrorCode;
import com.filldream.fastboot.common.entity.P;
import com.filldream.fastboot.common.util.Assert;
import com.filldream.fastboot.common.util.ListUtil;
import com.filldream.fastboot.core.LoginHolder;
import com.filldream.fastboot.core.cache.CacheMap;
import com.filldream.fastboot.core.cache.CacheUtil;
import com.filldream.fastboot.core.manager.MenuManager;
import com.filldream.fastboot.core.manager.RoleManager;
import com.filldream.fastboot.core.service.RoleService;
import com.filldream.fastboot.core.thread.ThreadPoolUtil;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;

/**
 * @author:RickSun
 * @date:2019/1/16 0016
 * description:
 **/
@AllArgsConstructor
@Service
@Transactional(rollbackFor = Exception.class)
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    private RoleMenuMapper roleMenuMapper;

    private SystemUserMapper systemUserMapper;

    private MenuManager menuManager;

    private RoleManager roleManager;

    @Override
    public P<Role> queryPageList(RoleListSTO roleListSTO) {
        QueryWrapper<Role> roleExample = new QueryWrapper<>();
        roleExample.orderByDesc( "update_time" );

        if(!StringUtils.isBlank(roleListSTO.getMemo())){
            roleExample.like("memo",roleListSTO.getMemo());
        }

        if(!StringUtils.isBlank(roleListSTO.getRoleName())){
            roleExample.like("role_name",roleListSTO.getRoleName());
        }

        if( roleListSTO.getDataScope() != null ){
            roleExample.eq("data_scope",roleListSTO.getDataScope());
        }

        //系统级管理员可以看到所有角色，而其他管理员是不能看到系统级角色的
        Role pcUserRole = LoginHolder.getPcUserRole();
        if(!pcUserRole.getId().equals(1L)){
            //查询我这个角色下的所有角色
            List<Long> childRoleIdList = roleManager.getChildRoleIdList(true,pcUserRole);
            if(ObjectUtils.isNotEmpty(childRoleIdList)){
                roleExample.in("id",childRoleIdList);
            }
        }

        Page page = page(roleListSTO.page(), roleExample);
        List<Role> roles = page.getRecords();

        //查找父级
        List<Long> parentIds = ListUtil.getParamList(roles, "pId", Long.class);
        Map<Long,String> parentMap = new HashMap<>();
        if( !parentIds.isEmpty() ){
            List<Role> parentRole = listByIds(parentIds);
            parentRole.forEach(e->{
                parentMap.put(e.getId(),e.getRoleName());
            });
        }

        roles.forEach( e ->{
            e.setPRoleName( parentMap.get(e.getPId()) );
        } );

        return P.autoSuccess(roles,page);
    }

    @Override
    public B setRoleMenu(SetRoleMenuSTO setRoleMenuSTO) {
        Assert.checkBoolean( !setRoleMenuSTO.getRoleId().equals(1L),ErrorCode.BASE_ERR.reMsg("超级管理员角色无需设置权限!") );
        //删除角色已选的菜单缓存
        List<Long> roleMenuIds = setRoleMenuSTO.getRoleMenuList();
        Long roleId = setRoleMenuSTO.getRoleId();
        if(roleMenuIds == null && roleMenuIds.isEmpty()){
            return B.fail();
        }

        Role role = roleManager.getById(roleId);
        if(roleMenuIds == null && roleMenuIds.isEmpty() || role == null){
            return B.fail();
        }

        Assert.isBoolean( role.getId().equals(LoginHolder.getPcRoleId()),ErrorCode.BASE_ERR.reMsg("您无权修改您当前的权限") );


        //删除所有权限
        roleMenuMapper.delete(
                new QueryWrapper<RoleMenu>().eq("role_id", roleId).eq("is_del", 0)
        );

        //添加权限
        List<String> newCodeList = new ArrayList<>();
        List<RoleMenu> newRoleMenuList = new ArrayList<>();
        for(Long id : roleMenuIds){
            //只添加最子级菜单
            Menu menu = menuManager.getById(id);
            if( menu.getIsMenu() <= 1 ){
                RoleMenu roleMenu = new RoleMenu();
                roleMenu.setMenuId(id);
                roleMenu.setCreateTime(new Date());
                roleMenu.setRoleId(roleId);
                newRoleMenuList.add(roleMenu);
                newCodeList.add( menu.getCode() );
            }
        }

        if( !newRoleMenuList.isEmpty() ){
            roleMenuMapper.batchInsert(newRoleMenuList);
        }

        //更新权限
        ThreadPoolUtil.R.getExecutor().execute( ()->{
            CacheUtil.cachePcRoleCodes( newCodeList, roleId);
        } );


        return B.success();
    }

    @Override
    public B delRole(Long id) {
        Assert.checkBoolean( !id.equals(1L),ErrorCode.BASE_ERR.reMsg("超级管理员角色不允许删改!") );

        //不允许自己删除自己的角色
        Assert.isBoolean(
                id.equals(LoginHolder.getPcRoleId()) && !id.equals(1L), ErrorCode.BASE_ERR.reMsg("禁止删除自己的角色")
        );

        //查询是否有管理员是这个角色的
        long count = systemUserMapper.selectCount(
                new QueryWrapper<SystemUser>().eq("role_id", id)
                        .eq("is_del", 0)
        );
        Assert.checkBoolean( count <= 0, ErrorCode.BASE_ERR.reMsg("当前角色正在被使用"));



        //查询子级角色
        long childRoleCount = count(new QueryWrapper<Role>().eq("p_id", id));
        Assert.checkBoolean( childRoleCount <= 0, ErrorCode.BASE_ERR.reMsg("请先删除子角色"));

        if( roleManager.del(id) > 0 ){
            CacheUtil.delKey(CacheMap.SYSTEM_ROLE_CODES.getKeyName(id));
        }

        return B.success();
    }

    @Override
    public B modify(Role role) {
        return B.checkSuccess(roleManager.modify( role ));
    }
}